#include "driver/mouse.h"



// ===============================================MouseEventHandler========================================

void MouseEventHandler::OnMouseMove(int8_t xoffset,int8_t yoffset){

}
void MouseEventHandler::OnMouseDown(uint8_t button){

}
void MouseEventHandler::OnMouseUp(uint8_t button){

}

MouseEventHandler::MouseEventHandler(/* args */)
{
}

MouseEventHandler::~MouseEventHandler()
{
}


// ===============================================MouseDriver========================================
MouseDriver::MouseDriver(InterruptManager* interruptManager,MouseEventHandler* handler)
:InterruptHandler(0x2C,interruptManager),
dataPort(0x60),
commandPort(0x64),
handler(handler)
{

    
    // commandPort.Write(0xD4);
    // dataPort.Write(0xF2);
    // dataPort.Read();
    // uint8_t id =  dataPort.Read();

    // char* foo = "ID: 0x00 \n";
    // char* hex = "0123456789ABCDEF";
    // foo[6] = hex[(id >> 4) & 0xF];
    // foo[7] = hex[id & 0xF];
    // printf(foo);
}

void MouseDriver::Activate(){
    
    offset = 0;
    buttons  = 0;
    static uint16_t* VideoMemory = (uint16_t*)0xb8000;
    VideoMemory[80 * 12 + 40] = ((VideoMemory[80 * 12 + 40] & 0xF000) >> 4)
                        | ((VideoMemory[80 * 12 + 40] & 0x0F00) << 4)
                        | (VideoMemory[80 * 12 + 40] & 0x00FF);
    commandPort.Write(0xA8); //active mouse interrupts
    commandPort.Write(0x20); //get current state

    uint8_t status = (dataPort.Read() | 2);
    commandPort.Write(0x60); //set state
    dataPort.Write(status);


    //set rate 
    commandPort.Write(0xD4);
    dataPort.Write(0xF3);
    while(!commandPort.Read() & 1) asm("pause");
    uint8_t ack = dataPort.Read();

    commandPort.Write(0xD4);
    dataPort.Write(8000); // 
    while(!commandPort.Read() & 1) asm("pause");
    ack = dataPort.Read();

    //get id 
    commandPort.Write(0xD4);
    dataPort.Write(0xf2); // 
    while(!commandPort.Read() & 1) asm("pause");
    ack = commandPort.Read();

    commandPort.Write(0xD4);
    dataPort.Write(0xF4); // 
     while(!commandPort.Read() & 1) asm("pause");
    dataPort.Read();
}


MouseDriver::~MouseDriver(){

}
uint32_t MouseDriver::HandleInterrupt(uint32_t esp){


    // deal the mouse data packet
    uint8_t status = commandPort.Read();
    if(!(status & 0x20) || handler == 0)
        return esp;
    int8_t x = 0, y = 0;
    buffer[offset] = dataPort.Read();
    offset = (offset + 1) % 3;

    if(offset == 0 )
    {

        if(buffer[0] != 0 && buffer[1] != 0){
        // if(buffer[0] & 0x10){
        //      x =  -(256 - buffer[1]);
             
        // }else{
        //     x = buffer[1];
        // }
        x = buffer[1];

        // if(buffer[0] & 0x20){
        //     y = -(256 - buffer[2]);
        // }else{
        //     y = buffer[2];
        // }

        y = buffer[2];

        handler->OnMouseMove(x, y);
        }

        for(uint8_t i = 0; i < 3; i++){
            if((buffer[0] & (0x01 << i)) != (buttons & (0x01 << i))){
              
                if(buffer[0] & (0x01 << i)){
                    switch (0)
                    {
                    case 0/* constant-expression */:
                        handler->OnMouseDown(0);
                        /* code */
                        break;
                    case 1/* constant-expression */:
                        handler->OnMouseDown(1);
                        /* code */
                        break;
                    case 2/* constant-expression */:
                        handler->OnMouseDown(2);
                        /* code */
                        break;
                    default:
                        handler->OnMouseDown(4);
                        break;
                    }
                }else{
                                        
                    switch (0)
                    {
                    case 0/* constant-expression */:
                        handler->OnMouseUp(0);
                        /* code */
                        break;
                    case 1/* constant-expression */:
                       handler->OnMouseUp(1);
                        /* code */
                        break;
                    case 2/* constant-expression */:
                        handler->OnMouseUp(2);
                        /* code */
                        break;
                    default:
                        handler->OnMouseUp(4);
                        break;
                    }
                }
            
                buttons = buffer[0];
            }
           
        }
    }

    return esp;
}
